/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "kh_sle_host.h"
#include "kh_sle_connect.h"
#include "kh_sle_ssap_server.h"
#include "sle_ssap_server_hal.h"
#include "sle_hilog.h"
#include "sle_ssap_config.h"
#include "sle_ssap_server_config.h"
#include "sle_lite_advance_setting.h"
#include <stdio.h>
#include <stdbool.h>
#include <stdlib.h>
#include <cmsis_os2.h>

#ifndef ServiceCallbackNumFlag
#define ServiceCallbackNumFlag
#define serviceCallbackNum  3
#endif  // ServiceCallbackNumFlag
static bool g_isSsapsServiceInit = false;
static SleSsapsCallbacks* g_ssapsCbs[serviceCallbackNum] = {NULL};
static SleSsapsHalCallbacks* g_SsapsHalCbs = NULL;
static osMutexId_t g_ssapsCbMuxHandle = 0;
static osSemaphoreId_t g_ssapsSemHandle = 0;
static SleErrorCode g_sleSsapsAsyncRet = SLE_ERR_UNKNOWN;
static uint32_t SleSsapsTimeOut = 300;

void OnSleHalStartServiceCallback(uint8_t serverId, uint16_t serviceHandle, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalStartServiceCallback serverId(%d), serviceHandle(%d)", serverId, serviceHandle);
    g_sleSsapsAsyncRet = errCode;
    osSemaphoreRelease(g_ssapsSemHandle);
}

void OnSleHalRemoveAllServicesCallback(uint8_t serverId, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalRemoveAllServicesCallback serverId(%d)", serverId);
    g_sleSsapsAsyncRet = errCode;
    osSemaphoreRelease(g_ssapsSemHandle);
}

void OnSleHalReceiveReadRequestCallback(uint8_t serverId, uint16_t connectId, SsapsReqReadCbParam *reqReadCbPara,
                SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalReceiveReadRequestCallback");
    SLE_ASSERT_AND_RETURN(reqReadCbPara != NULL);
    SsapsReqReadCbParam reqReadCbParaCb;
    memcpy(&reqReadCbParaCb, reqReadCbPara, sizeof(SsapsReqReadCbParam));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapsCbs[i] != NULL && g_ssapsCbs[i]->OnRequestReadCb != NULL) {
            g_ssapsCbs[i]->OnRequestReadCb(errCode, serverId, connectId, &reqReadCbParaCb);
        }
    }
}

void OnSleHalReceiveWriteRequestCallback(uint8_t serverId, uint16_t connectId, SsapsReqWriteCbPara *writeCbPara,
                SleHalErrorCode errCode)
{
#if 0
    SLE_LOGD("OnSleHalReceiveWriteRequestCallback");
#endif
    SLE_ASSERT_AND_RETURN(writeCbPara != NULL);
    SsapsReqWriteCbPara writeCbParaCb;
    memcpy(&writeCbParaCb, writeCbPara, sizeof(SsapsReqWriteCbPara));
    for(int i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapsCbs[i] != NULL && g_ssapsCbs[i]->OnRequestWriteCb != NULL) {
            g_ssapsCbs[i]->OnRequestWriteCb(errCode, serverId, connectId, &writeCbParaCb);
        }
    }
}

void OnSleHalChangeMtuCallback(uint8_t serverId, uint16_t connectId ,const SsapMtuInfo *mtuInfo, SleHalErrorCode errCode)
{
    SLE_LOGD("OnSleHalChangeMtuCallback");
    SLE_ASSERT_AND_RETURN(mtuInfo != NULL);
    SetRecomSendDataSizeAdvance(connectId, mtuInfo->mtuSize);
    SsapMtuInfo mtuInfoCb;
    memcpy(&mtuInfoCb, mtuInfo, sizeof(SsapMtuInfo));
    uint16_t data_len = mtuInfo->mtuSize + DATA_LEN_BIGGER;
    SleHalErrorCode ret = SleConnectHalSetDataLength(connectId, data_len);
    SLE_ASSERT_AND_RETURN_LOG(ret == SLE_HAL_SUCCESS, "SleConnectHalSetDataLength fail(%d)", ret);
    for(int i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapsCbs[i] != NULL && g_ssapsCbs[i]->OnChangeMtuCb != NULL) {
            g_ssapsCbs[i]->OnChangeMtuCb(errCode, serverId, connectId, &mtuInfoCb);
        }
    }
}

SleErrorCode InitSleSsapsService(void)
{
    SLE_LOGD("InitSleSsapsService");
    SLE_ASSERT_AND_RETURN_RET(g_isSsapsServiceInit == false, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    ret = InitSleSsapsHal();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);

    if (g_ssapsSemHandle == 0) {
        g_ssapsSemHandle = osSemaphoreNew(1, 0, NULL);
    }

    if (g_ssapsCbMuxHandle == 0) {
      osMutexAttr_t attr = {
            .name = "sle_ssaps_mux",
        };
        g_ssapsCbMuxHandle = osMutexNew(&attr);
    }

    if(g_SsapsHalCbs == NULL) {
        g_SsapsHalCbs = (SleSsapsHalCallbacks*)malloc(sizeof(SleSsapsHalCallbacks));
        SLE_ASSERT_AND_RETURN_RET(g_SsapsHalCbs != NULL, SLE_ERR_SYSTEM_WRONG);
        g_SsapsHalCbs->OnSsapsServiceStartedCb = OnSleHalStartServiceCallback;
        g_SsapsHalCbs->OnSsapsAllServiceRemovedCb = OnSleHalRemoveAllServicesCallback;
        g_SsapsHalCbs->OnSsapsRecvReadReqCb = OnSleHalReceiveReadRequestCallback;
        g_SsapsHalCbs->OnSsapsRecvWriteReqCb = OnSleHalReceiveWriteRequestCallback;
        g_SsapsHalCbs->OnSsapsMtuChangeCb = OnSleHalChangeMtuCallback;
    }
    ret = (SleErrorCode)SleSsapsHalRegisterCallbacks(g_SsapsHalCbs);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    g_isSsapsServiceInit = true;
    return ret;
}

SleErrorCode CheckCanOprateSsaps(void)
{
    SLE_ASSERT_AND_RETURN_RET(g_isSsapsServiceInit == true, SLE_ERR_NOT_READY);
    SleDeviceState hostState;
    SleErrorCode ret = GetSleState(&hostState);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    SLE_ASSERT_AND_RETURN_RET(hostState == SLE_HOST_STATE_ENABLED, SLE_ERR_STATUS_WRONG);
    return SLE_NO_ERROR;
}

SleErrorCode DeinitSleSsapsService(void)
{
    SLE_LOGD("DeinitSleSsapsService");
    SleErrorCode ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = DeinitSleSsapsHal();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);

    if (g_ssapsCbMuxHandle == 0) {
        SLE_LOGW("g_ssapsCbMuxHandle is 0");
        return SLE_NO_ERROR;
    }
    osMutexDelete(g_ssapsCbMuxHandle);
    g_ssapsCbMuxHandle = 0;
    osSemaphoreDelete(g_ssapsSemHandle);
    g_ssapsSemHandle = 0;
    g_isSsapsServiceInit = false;
    return ret;
}

static SleErrorCode CheckSsapServerUuid(const SleUuid *uuid)
{
    if (uuid->len == 0) {
        return SLE_NO_ERROR;
    }
    bool AllZero = true;
    bool AllFF = true;
    for (int i = 0; i < UUID_LEN; ++i) {
        if (uuid->uuid[i] != 0x00) {
            AllZero = false;
        }
        if (uuid->uuid[i] != 0xFF) {
            AllFF = false;
        }
    }
    SLE_ASSERT_AND_RETURN_RET_LOG((!AllZero && !AllFF), SLE_ERR_INVALID_PARAM, "check uuid error!");
    return SLE_NO_ERROR;
}

SleErrorCode AddSsapServer(const SleUuid *appUuid, uint8_t *serverId)
{
    SLE_LOGD("AddSsapServer");
    SLE_ASSERT_AND_RETURN_RET(appUuid != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapServerUuid(appUuid);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serverId != NULL, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalAddServer(appUuid, serverId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode RemoveSsapServer(uint8_t serverId)
{
    SLE_LOGD("RemoveSsapServer");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalRemoveServer(serverId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode AddService(uint8_t serverId, const SleUuid* serviceUuid, bool isPrimary, uint16_t *srviceHandle)
{
    SLE_LOGD("AddService");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapServerUuid(serviceUuid);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(srviceHandle != NULL, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalAddService(serverId, serviceUuid, isPrimary, srviceHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckSsapsPropertyParam(const SsapsPropertyParam *param)
{
    SleErrorCode ret = CheckSsapServerUuid(&param->uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param server property uuid error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->permissions >= SSAP_PERMISSION_CAN_READ && param->permissions <= 0x1F,
        SLE_ERR_INVALID_PARAM, "param server property permission error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->opIndication >= SSAP_OPERATEIND_BIT_READ && param->opIndication <= 0x13F,
        SLE_ERR_INVALID_PARAM, "param server property indication error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->valueLen != 0, SLE_ERR_INVALID_PARAM,
        "param server property value length error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->value, SLE_ERR_INVALID_PARAM,
        "param server property value ptr not init error!");
    return SLE_NO_ERROR;
}

SleErrorCode AddProperty(uint8_t serverId, uint16_t serviceHandle, const SsapsPropertyParam *param, uint16_t *propHandle)
{
    SLE_LOGD("AddProperty");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serviceHandle != 0, SLE_ERR_INTERNAL_WRONG);
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapsPropertyParam(param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(propHandle != NULL, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalAddProperty(serverId, serviceHandle, param, propHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckSsapsDescriptorParam(const SsapsDescriptorParam *param)
{
    SleErrorCode ret = CheckSsapServerUuid(&param->uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM, "param server descriptor uuid error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->permissions >= SSAP_PERMISSION_CAN_READ && param->permissions <= 0x1F,
        SLE_ERR_INVALID_PARAM, "param server descriptor permission error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->operateInd >= SSAP_OPERATEIND_BIT_READ && param->operateInd <= 0x13F,
        SLE_ERR_INVALID_PARAM, "param server descriptor indication error!");
    SLE_ASSERT_AND_RETURN_RET_LOG((param->type >= SSAP_PROPERTY_TYPE_VALUE_TYPE && param->type <= SSAP_DESCRIPTOR_TYPE_RFU_TYPE) ||
        param->type == SSAP_DESCRIPTOR_TYPE_CUSTOM_TYPE, SLE_ERR_INVALID_PARAM, "param server descriptor type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->valueLen != 0, SLE_ERR_INVALID_PARAM,
        "param server descriptor value length error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->value, SLE_ERR_INVALID_PARAM,
        "param server descriptor value ptr not init error!");
    return SLE_NO_ERROR;
}

SleErrorCode AddDescriptor(uint8_t serverId, uint16_t serviceHandle, uint16_t propHandle
        , const SsapsDescriptorParam *descParam, uint16_t *descHandle)
{
    SLE_LOGD("AddDescriptor");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serviceHandle != 0, SLE_ERR_INTERNAL_WRONG);
    SLE_ASSERT_AND_RETURN_RET(propHandle > 1, SLE_ERR_INTERNAL_WRONG);
    SLE_ASSERT_AND_RETURN_RET(descParam != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapsDescriptorParam(descParam);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(descHandle != NULL, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalAddDescriptor(serverId, serviceHandle, propHandle, descParam, descHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode StartService(uint8_t serverId, uint16_t serviceHandle)
{
    SLE_LOGD("StartService");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(serviceHandle != 0, SLE_ERR_INTERNAL_WRONG);
    SleErrorCode ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalStartService(serverId, serviceHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    osStatus_t uwRet = osSemaphoreAcquire(g_ssapsSemHandle, SleSsapsTimeOut);
    SLE_ASSERT_AND_RETURN_RET(uwRet != osErrorTimeout, SLE_ERR_TIME_OUT);
    ret = g_sleSsapsAsyncRet;
    g_sleSsapsAsyncRet = SLE_ERR_UNKNOWN;
    return ret;
}

SleErrorCode RemoveAllServices(uint8_t serverId)
{
    SLE_LOGD("RemoveAllServices");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalRemoveAllServices(serverId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    osStatus_t uwRet = osSemaphoreAcquire(g_ssapsSemHandle, SleSsapsTimeOut);
    SLE_ASSERT_AND_RETURN_RET(uwRet != osErrorTimeout, SLE_ERR_TIME_OUT);
    ret = g_sleSsapsAsyncRet;
    g_sleSsapsAsyncRet = SLE_ERR_UNKNOWN;
    return ret;
}

static SleErrorCode CheckSsapsSendRspParam(const SsapsSendRspParam *param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param->status >= ERROR_CODE_SSAP_INVALID_PDU && param->status < ERROR_CODE_SSAP_VALUE_OUT_OF_RANGE,
        SLE_ERR_INVALID_PARAM, "param server response status error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->value, SLE_ERR_INVALID_PARAM,
        "param server response value ptr not init error!");
    return SLE_NO_ERROR;
}

SleErrorCode SendResponse(uint8_t serverId, uint16_t connectId, const SsapsSendRspParam *param)
{
    SLE_LOGD("SendResponse");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapsSendRspParam(param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalSendResponse(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckSsapsNotifyParam(const SsapsNotifyParam *param)
{
    SLE_ASSERT_AND_RETURN_RET_LOG(param->type == SSAP_PROPERTY_TYPE_VALUE_TYPE,
        SLE_ERR_INVALID_PARAM, "param server notify type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->valueLen != 0, SLE_ERR_INVALID_PARAM,
        "param server notify value length error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->value, SLE_ERR_INVALID_PARAM,
        "param server notify value ptr not init error!");
    return SLE_NO_ERROR;
}

SleErrorCode NotifyIndicate(uint8_t serverId, uint16_t connectId, const SsapsNotifyParam *param)
{
    SLE_LOGD("NotifyIndicate");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapsNotifyParam(param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalNotifyIndicate(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static SleErrorCode CheckSsapsNotyfyByUuidParam(const SsapsNotyfyByUuidParam *param)
{
    SleErrorCode ret = CheckSsapServerUuid(&param->uuid);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM,
        "param server notify by uuid property uuid error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->startHandle <= param->endHandle,
        SLE_ERR_INVALID_PARAM, "param server notify by uuid handle error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->type == SSAP_PROPERTY_TYPE_VALUE_TYPE,
        SLE_ERR_INVALID_PARAM, "param server notify by uuid type error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->valueLen != 0,
        SLE_ERR_INVALID_PARAM, "param server notify by uuid value length error!");
    SLE_ASSERT_AND_RETURN_RET_LOG(param->value, SLE_ERR_INVALID_PARAM,
        "param server notify by uuid value ptr not init error!");
    return SLE_NO_ERROR;
}

SleErrorCode NotifyIndicateByUuid(uint8_t serverId, uint16_t connectId, const SsapsNotyfyByUuidParam *param)
{
    SLE_LOGD("NotifyIndicateByUuid");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(connectId < SLE_MAX_CONNECT_ID_NUM, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(param != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckSsapsNotyfyByUuidParam(param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, SLE_ERR_INVALID_PARAM);
    ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = CheckIsConnected(connectId);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalNotifyIndicateByUuid(serverId, connectId, param);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode SetServerMtuInfo(uint8_t serverId, const SsapMtuInfo *mtuInfo)
{
    SLE_LOGD("SetServerMtuInfo");
    SLE_ASSERT_AND_RETURN_RET(serverId <= SSAP_SERVER_NUM_MAX, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(mtuInfo != NULL, SLE_ERR_INVALID_PARAM);
    SleErrorCode ret = CheckCanOprateSsaps();
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    ret = (SleErrorCode)SleSsapsHalSetMtuInfo(serverId, mtuInfo);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

static bool CheckIsRegistered(const SleSsapsCallbacks *ssapsCallbacks)
{
    for(uint8_t i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapsCbs[i] == ssapsCallbacks) {
            return true;
        }
    }
    return false;
}

SleErrorCode RegisterSsapServerCallbacks(SleSsapsCallbacks *ssapsCallbacks)
{
    SLE_LOGD("RegisterSsapServerCallbacks");
    SLE_ASSERT_AND_RETURN_RET(ssapsCallbacks != NULL, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(g_isSsapsServiceInit == true, SLE_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(CheckIsRegistered(ssapsCallbacks) == false, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_UNKNOWN;
    uint8_t count = 0;
    osMutexAcquire(g_ssapsCbMuxHandle, 0);
    for(; count < serviceCallbackNum; count++) {
        if(g_ssapsCbs[count] == NULL) {
            g_ssapsCbs[count] = ssapsCallbacks;
            ret = SLE_NO_ERROR;
            break;
        }
    }
    osMutexRelease(g_ssapsCbMuxHandle);
    SLE_ASSERT_AND_RETURN_RET(count < serviceCallbackNum, SLE_ERR_NO_MEM);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}

SleErrorCode UnregisterSsapServerCallbacks(SleSsapsCallbacks *ssapsCallbacks)
{
    SLE_LOGD("UnregisterSsapServerCallbacks");
    SLE_ASSERT_AND_RETURN_RET(ssapsCallbacks != NULL, SLE_ERR_INVALID_PARAM);
    SLE_ASSERT_AND_RETURN_RET(g_isSsapsServiceInit == true, SLE_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(CheckIsRegistered(ssapsCallbacks) == true, SLE_NO_ERROR);
    SleErrorCode ret = SLE_ERR_FAILED;
    osMutexAcquire(g_ssapsCbMuxHandle, 0);
    for(uint8_t i = 0; i < serviceCallbackNum; i++) {
        if (g_ssapsCbs[i] == ssapsCallbacks) {
            g_ssapsCbs[i] = NULL;
            ret = SLE_NO_ERROR;
            break;
        }
    }
    osMutexRelease(g_ssapsCbMuxHandle);
    SLE_ASSERT_AND_RETURN_RET(ret == SLE_NO_ERROR, ret);
    return ret;
}